import Konva from 'konva'
import { Utils } from 'orion-common'
import TUtils from './node-utils.js'

/**
 * 基础节点，只有背景图案颜色，关闭按钮
 */
class TNode {
  constructor (config) {
    this.config = Utils.lodash.merge({
      width: TUtils.node.minWidth,
      height: TUtils.node.minHeight,
      fill: '#ffffff',
      stroke: '#000000',
      strokeWidth: 1,
      dragDistance: TUtils.node.dragDistance,
      protos: { node: true },
      uid: Utils.common.uniqid(),
      canClose: true,
      canMove: false,
      acceptChild: false,
      context: null  // 关联上下文数据
    }, config)
 
    this.isSelected = false
    this.isDragging = false
    this.children = []

    this.dropingChild = null

    this.config.type = 'node'
    this.root = new Konva.Group({
      x: this.config.x,
      y: this.config.y,
      draggable: this.config.canMove,
      dragDistance: this.config.dragDistance,
      name: this.config.type,  // 记录节点类型
      id: this.config.uid,
      listening: true
    })
    this.root.setAttr(`@${this.config.type}`, this)

    // 创建背景
    this.background = this.createBackground()


    // 创建关闭按钮
    if (this.config.canClose) {
      this.close = this.createCloseButton({
        size: 10,
        uid: this.config.uid,
        action: () => {
          let stage = this.stage()
          if (stage && stage.isReadOnly()) {
            return
          }
          this.destroy()
        }
      })
      this.root.add(this.close)
    }

    // 创建内容
    this.createBody()

    this.adjust()
  }

  /**
   * 创建背景
   */
  createBackground () {
    return new Konva.Rect({
      x: 0,
      y: 0,
      width: this.config.width,
      height: this.config.height,
      fill: this.config.fill,
      stroke: this.config.stroke,
      strokeWidth: this.config.strokeWidth
    })
  }

  /**
   * 创建节点内容
   */
  createBody () {
    this.body = new Konva.Group({
      x: 0,
      y: 0,
      width: this.config.width,
      height: this.config.height,
      name: 'node-body'
    })
    this.root.add(this.body)
  }

  /**
   * 获取父节点
   */
  parent () {
    let p = this.root.getParent()
    while (p) {
      if (p.hasName('node')) {
        break
      }
      p = p.getParent()
    }
    return p ? p.getAttr('@node') : null
  }

  /**
   * 
   * @param {*} parent
   */
  hasParent (parent) {
    let p = this.parent()
    while (p && p !== parent) {
      p = p.parent()
    }
    return p === parent
  }

  /**
   * 从父节点删除
   */
  remove () {
  }

  /**
   * 删除自己
   */
  destroy (self = true, notify = true) {
    this.root.destroy()
  }

  /**
   * 创建close按钮
   * @param option
   * {
   *   uid:
   *   x:
   *   y:
   *   size:
   *   background:
   *   action:
   * }
   */
  createCloseButton (option) {
    let opt = Utils.lodash.merge({
      x: 0,
      y: 0,
      size: 10,
      background: 'transparent',
      stroke: '#ddd',
      strokeWidth: 2,
      lineCap: 'round',
      lineJoin: 'round'
    }, option)

    // 删除按钮
    let close = new Konva.Group({
      x: opt.x,
      y: opt.y,
      rotation: 45,
      name: 'node-close'
    })

    let bg = new Konva.Circle({
      x: 0,
      y: 0,
      radius: opt.size / 2,
      fill: opt.background,
      stroke: opt.background
    })
    close.add(bg)

    let lineRadius = opt.size / 2 - 2
    let hline = new Konva.Line({
      points: [-lineRadius, 0, lineRadius, 0],
      stroke: opt.stroke,
      strokeWidth: opt.strokeWidth,
      lineCap: 'round',
      lineJoin: 'round'
    })
    close.add(hline)

    let vline = new Konva.Line({
      points: [0, -lineRadius, 0, lineRadius],
      stroke: opt.stroke,
      strokeWidth: opt.strokeWidth,
      lineCap: 'round',
      lineJoin: 'round'
    })
    close.add(vline)
    close.on('mousedown', function(evt) {
      opt.action && opt.action()
      evt.cancelBubble = true
    })

    close.on('mouseout', function (evt) {
      vline.setAttr('stroke', opt.stroke)
      hline.setAttr('stroke', opt.stroke)
      this.getLayer().draw()
      evt.cancelBubble = true
    })

    close.on('mouseover', function (evt) {
      vline.setAttr('stroke', '#FF3030')
      hline.setAttr('stroke', '#FF3030')
      this.getLayer().draw()
      evt.cancelBubble = true
    })

    return close
  }

  /**
   * 调整宽度
   * @param {*} w 宽度
   */
  resizeWidth (w) {
    if (w) {
      // 调整背景
      this.background.width(w)
    }
    // 调整关闭按钮
    if (this.close) {
      let width = this.background.width()
      let bbox = this.close.getClientRect()
      // 调整close按钮
      this.close.position({
        x: width - bbox.width / 2,
        y: bbox.height / 2
      })
    }
  }

  /**
   * 调整布局
   */
  adjust (option) {
    let needWidth = TUtils.node.minWidth
    let bbox = this.body.getClientRect({
      skipTransform: true
    })
    needWidth = Math.max(needWidth, bbox.width)

    this.resizeWidth(needWidth)
    this.background.height(bbox.height + 8)
  }

  /**
   * 
   * @param {*} flag 
   */
  selected (flag) {
    this.isSelected = flag
    this.background.strokeWidth(this.isSelected ? 2 : 1)
    this.background.stroke(this.isSelected ? TUtils.node.highlight : this.config.stroke)
  }
  /**
   *  刷新
   */
  refresh () {
    this.root.getLayer().draw()
  }

  /**
   * 
   */
  nodeType () {
    return this.config.type
  }

  /**
   * 判断类型
   * @param {*} type 
   */
  isType (type) {
    return this.config.protos[type] == true 
  }

  /**
   * 树层级 root = 0
   */
  level () {
    let l = 0
    let p = this.parent()
    while (p) {
      l += 1
      p = p.parent()
    }
    return l
  }

  /**
   * 
   */
  toJson () {
    return {
      ...this.config
    }
  }

  /**
   * 
   */
  canMove () {
    return this.config.canMove
  }

  canAcceptChild () {
    return this.config.acceptChild
  }

  dropChild(child) {
    this.dropingChild = child
    this.adjust()
  }

  /**
   * 
   */
  isVisible () {
    return this.root.visible()
  }

  /**
   * knova节点
   */
  knode () {
    return this.root
  }

  /**
   * 获取TStage对象
   */
  stage () {
    let st = this.root.getStage()
    return st ? st.getAttr('@stage') : null
  }

  /**
   * 获取位置
   */
  position () {
    return this.root.position()
  }

  /**
   * 
   */
  size () {
    return this.background.size()
  }

  /**
   * 
   */
  id () {
    return this.root.id()
  }

  /**
   * 
   * @param {*} show 
   */
  visible (show) {
    return this.root.visible(show)
  }

    /**
     * 
     */
  enterDragging() {
    this.isDragging = true
    let parent = this.parent()
    if (parent) {
      this.root.zIndex(parent.childCount())
    }
  }

  exitDragging() {
    this.isDragging = false
    this.root.zIndex(1)
  }

  dragging() {
    return this.isDragging
  }

  childCount() {
    return this.children.length
  }
}

export default TNode
